package json.fastjson;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.alibaba.fastjson.serializer.SerializerFeature;
import json.DateFormat;
import json.User;
import org.junit.Test;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @describe: fastjson是阿里开发的一款专门用于Java开发的包，可以方便的实现json对象与JavaBean对象的转换，
 * 实现JavaBean对象与json字符串的转换，实现json对象与json字符串的转换。
 * @author: houkai
 */
public class FastJsonDemo {

    /**
     * 序列化和反序列化
     */
    @Test
    public void aTest() {
        User user = User.init();
        System.out.println(JSON.toJSONString(user));

        String json = "{\"age\":19,\"homeAddress\":\"陕西西安\",\"name\":\"张三\",\"sex\":true}";
        user = JSON.parseObject(json, User.class);
        System.out.println(user.toString());
    }

    /**
     * 泛型 反序列化支持
     * 可以通过 TypeReference 指定类型
     */
    @Test
    public void bTest() {
        String jsonss = "[\"1\",\"2\",\"3\"]";
        List obj = JSON.parseObject(jsonss, new TypeReference<List<String>>() {
        });
        System.out.println(obj);
    }

    /**
     * 时间序列化和反序列化
     * 反序列化能够自动识别如下日期格式：
     * ISO-8601日期格式
     * yyyy-MM-dd
     * yyyy-MM-dd HH:mm:ss
     * yyyy-MM-dd HH:mm:ss.SSS
     * 毫秒数字
     * 毫秒数字字符串
     * .NET JSON日期格式
     * new Date(1982932381111)
     */
    @Test
    public void cTest() {
        //反序列化
        String dateFormatStr = "{\"d\":\"2019-09-09 09:09:09\"}";
        DateFormat dateFormat = JSON.parseObject(dateFormatStr, DateFormat.class);
        //序列化
        String str = JSON.toJSONStringWithDateFormat(dateFormat, "yyyy-MM-dd HH:mm:ss");
        System.out.println(str);
    }

    /**
     * 使用 @JSONField(name="") 对属性进行序列化或者反序列化时的重命名
     */
    @Test
    public void dTest() {
        String str = "{\"xingming\":\"zha\"}";
        SerialReName serialReName = JSON.parseObject(str, SerialReName.class);
        System.out.println(serialReName);
    }

    /**
     * 对null值的处理
     * QuoteFieldNames———-输出key时是否使用双引号,默认为true
     * WriteMapNullValue——–是否输出值为null的字段,默认为false
     * WriteNullNumberAsZero—-数值字段如果为null,输出为0,而非null
     * WriteNullListAsEmpty—–List字段如果为null,输出为[],而非null
     * WriteNullStringAsEmpty—字符类型字段如果为null,输出为"",而非null
     * WriteNullBooleanAsFalse–Boolean字段如果为null,输出为false,而非null
     */
    @Test
    public void eTest() {
        Map<String, Object> jsonMap = new HashMap<String, Object>();
        jsonMap.put("a", 1);
        jsonMap.put("b", "");
        jsonMap.put("c", null);
        String str = JSONObject.toJSONString(jsonMap, SerializerFeature.WriteMapNullValue);
        System.out.println(str);
    }

    /**
     * JSON 操作
     */
    @Test
    public void fTest() {
        JSONObject object = new JSONObject();
        object.putIfAbsent("key", "value");  //不会覆盖
        object.put("key", new Date());   //会覆盖
        System.out.println(object.toJSONString());
    }

    /*关于内部类不序列化
        fastJson 内部类一定是static内部类，且字段为public，否则不能序列化数据到内部类字段上。
    demo：
    public class PersonVO {
        public Customer xxx;
        public static class Customer{
            public Long customerId;
            public String customerName;
        }
    }
    */


    /*忽略属性
    * FastJson序列化时（即转成JSON字符串时），可以过滤掉部分字段，或者只保留部分字段
    *
    * 方法一：FastJson的注解
    * @JSONField(serialize = false)
    * private String name;
    *
    * 方法二：JAVA关键字，　在实体字段前面，使用transient关键字，表示该字段不参与序列化，转JSON字符串时就可以忽略掉该字段。
    *   因为是JAVA关键字所以也会影响该字段其他序列化操作。
    *  @JSONField(name = "AGE")
    *  private transient String age;
    *
    * 方法三：FastJson的属性名过滤器SimplePropertyPreFilter，来过滤/指定的属性名，然后在转JSON的时候，带上过滤器参数即可。
    *
    * SimplePropertyPreFilter filter = new SimplePropertyPreFilter();
    * filter.getExcludes().add("PHONE");
    * System.out.println(JSONObject.toJSONString(u, filter));
    * 如果需要保留的参数比较少，也可以反过来，使用 filter.getIncludes().add("PHONE");
    * */
}
